// $Id: array_iterator.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_DETAIL_ARRAY_ITERATOR_HPP
#define XPCOM_DETAIL_ARRAY_ITERATOR_HPP

#include <xpcom/config.hpp>
#include <cstddef>
#include <iterator>
#include <xpcom/assert.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {
namespace detail {

// array_const_iterator
template <typename Traits>
class array_const_iterator
{
    typedef array_const_iterator<Traits> this_type;
public:
    typedef Traits                                  traits_type;
    typedef typename traits_type::element_type      element_type;

    typedef std::random_access_iterator_tag         iterator_category;
    typedef typename traits_type::value_type        value_type;
    typedef std::ptrdiff_t                          difference_type;
    typedef typename traits_type::const_pointer     pointer;
    typedef typename traits_type::const_reference   reference;

    array_const_iterator() :
        ptr_(0)
    {
    }

    explicit array_const_iterator(element_type* ptr) :
        ptr_(ptr)
    {
    }

    // Forward iterator requirements
    reference operator*() const
    {
        XPCOM_ASSERT(ptr_);
        return traits_type::const_ref(*ptr_);
    }

    pointer operator->() const
    {
        return &**this;
    }

    this_type& operator++()
    {
        ++ptr_;
        return *this;
    }

    this_type operator++(int)
    {
        return this_type(ptr_++);
    }

    // Bidirectional iterator requirements
    this_type& operator--()
    {
        --ptr_;
        return *this;
    }

    this_type operator--(int)
    {
        return this_type(ptr_--);
    }

    // Random access iterator requirements
    reference operator[](difference_type n) const
    {
        return traits_type::const_ref(ptr_[n]);
    }

    this_type& operator+=(difference_type n)
    {
        ptr_ += n;
        return *this;
    }

    this_type operator+(difference_type n) const
    {
        return this_type(ptr_ + n);
    }

    this_type& operator-=(difference_type n)
    {
        ptr_ -= n;
        return *this;
    }

    this_type operator-(difference_type n) const
    {
        return this_type(ptr_ - n);
    }

    difference_type operator-(const this_type& rhs) const
    {
        return ptr_ - rhs.ptr_;
    }

    // Iterator comparison
    // Forward iterator requirements
    bool operator==(const this_type& rhs) const
    {
        return ptr_ == rhs.ptr_;
    }

    bool operator!=(const this_type& rhs) const
    {
        return ptr_ != rhs.ptr_;
    }

    // Random access iterator requirements
    bool operator<(const this_type& rhs) const
    {
        return ptr_ < rhs.ptr_;
    }

    bool operator>(const this_type& rhs) const
    {
        return ptr_ > rhs.ptr_;
    }

    bool operator<=(const this_type& rhs) const
    {
        return ptr_ <= rhs.ptr_;
    }

    bool operator>=(const this_type& rhs) const
    {
        return ptr_ >= rhs.ptr_;
    }

protected:
    element_type* ptr_;
};

template <typename Traits>
inline array_const_iterator<Traits> operator+(
        typename array_const_iterator<Traits>::difference_type n,
        array_const_iterator<Traits> iter)
{
    return iter += n;
}

// array_iterator
template <typename Traits>
class array_iterator : public array_const_iterator<Traits>
{
    typedef array_iterator<Traits> this_type;
    typedef array_const_iterator<Traits> base_type;
public:
    typedef Traits                              traits_type;
    typedef typename traits_type::element_type  element_type;

    typedef std::random_access_iterator_tag     iterator_category;
    typedef typename traits_type::value_type    value_type;
    typedef std::ptrdiff_t                      difference_type;
    typedef typename traits_type::pointer       pointer;
    typedef typename traits_type::reference     reference;

    array_iterator() :
        base_type()
    {
    }

    explicit array_iterator(element_type* ptr) :
        base_type(ptr)
    {
    }

    // Forward iterator requirements
    reference operator*() const
    {
        XPCOM_ASSERT(ptr_);
        return traits_type::ref(*ptr_);
    }

    pointer operator->() const
    {
        return &**this;
    }

    this_type& operator++()
    {
        ++ptr_;
        return *this;
    }

    this_type operator++(int)
    {
        return this_type(ptr_++);
    }

    // Bidirectional iterator requirements
    this_type& operator--()
    {
        --ptr_;
        return *this;
    }

    this_type operator--(int)
    {
        return this_type(ptr_--);
    }

    // Random access iterator requirements
    reference operator[](difference_type n) const
    {
        return traits_type::ref(ptr_[n]);
    }

    this_type& operator+=(difference_type n)
    {
        ptr_ += n;
        return *this;
    }

    this_type operator+(difference_type n) const
    {
        return this_type(ptr_ + n);
    }

    this_type& operator-=(difference_type n)
    {
        ptr_ -= n;
        return *this;
    }

    this_type operator-(difference_type n) const
    {
        return this_type(ptr_ - n);
    }

    difference_type operator-(const this_type& rhs) const
    {
        return ptr_ - rhs.ptr_;
    }

protected:
    using base_type::ptr_;
};

template <typename Traits>
inline array_iterator<Traits> operator+(
        typename array_iterator<Traits>::difference_type n,
        array_iterator<Traits> iter)
{
    return iter += n;
}

} // namespace xpcom::detail
} // namespace xpcom

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_DETAIL_ARRAY_ITERATOR_HPP
